﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestConstructor.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Tests.CrsSparseMatrixTest
{
    #region Usings

    using System;

    using ExulLibrary.Exceptions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for the constructor of <see cref="CrsSparseMatrix{T}"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.CrsSparseMatrix{T}")]
    public sealed class TestConstructor
    {
        /// <summary>
        ///     Tests the constructor when all parameters have valid values and specifies square matrix
        ///     when data parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenParametersAreValidForSquareMatrixWhenDataIsNull()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columns = new[] { 0 };

            // Act
            var matrix = new CrsSparseMatrix<object>(1, 1, rowsBegins, columns);

            // Assert
            Assert.That(matrix.RowsCount, Is.EqualTo(1));
            Assert.That(matrix.ColumnsCount, Is.EqualTo(1));
            Assert.That(matrix.IsSquare, Is.True);
            Assert.That(matrix.RowsBegins, Is.SameAs(rowsBegins));
            Assert.That(matrix.ColumnsIndexes, Is.SameAs(columns));
            Assert.That(matrix.Values, Is.Not.Null & Has.Length.EqualTo(columns.Length));
        }

        /// <summary>
        ///     Tests the constructor when all parameters have valid values and specifies square matrix
        ///     when data parameter is not <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenParametersAreValidForSquareMatrixWhenDataIsNotNull()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columns = new[] { 0 };
            var data = new object[1];

            // Act
            var matrix = new CrsSparseMatrix<object>(1, 1, rowsBegins, columns, data);

            // Assert
            Assert.That(matrix.RowsCount, Is.EqualTo(1));
            Assert.That(matrix.ColumnsCount, Is.EqualTo(1));
            Assert.That(matrix.IsSquare, Is.True);
            Assert.That(matrix.RowsBegins, Is.SameAs(rowsBegins));
            Assert.That(matrix.ColumnsIndexes, Is.SameAs(columns));
            Assert.That(matrix.Values, Is.SameAs(data));
        }

        /// <summary>
        ///     Tests the constructor when all parameters have valid values and specifies non-square matrix
        ///     when data parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenParametersAreValidForNonSquareMatrixWhenDataIsNull()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columns = new[] { 0 };

            // Act
            var matrix = new CrsSparseMatrix<object>(1, 2, rowsBegins, columns);

            // Assert
            Assert.That(matrix.RowsCount, Is.EqualTo(1));
            Assert.That(matrix.ColumnsCount, Is.EqualTo(2));
            Assert.That(matrix.IsSquare, Is.False);
            Assert.That(matrix.RowsBegins, Is.SameAs(rowsBegins));
            Assert.That(matrix.ColumnsIndexes, Is.SameAs(columns));
            Assert.That(matrix.Values, Is.Not.Null & Has.Length.EqualTo(columns.Length));
        }

        /// <summary>
        ///     Tests the constructor when all parameters have valid values and specifies non-square matrix
        ///     when data parameter is not <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenParametersAreValidForNonSquareMatrixWhenDataIsNotNull()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columns = new[] { 0 };
            var data = new object[1];

            // Act
            var matrix = new CrsSparseMatrix<object>(1, 2, rowsBegins, columns, data);

            // Assert
            Assert.That(matrix.RowsCount, Is.EqualTo(1));
            Assert.That(matrix.ColumnsCount, Is.EqualTo(2));
            Assert.That(matrix.IsSquare, Is.False);
            Assert.That(matrix.RowsBegins, Is.SameAs(rowsBegins));
            Assert.That(matrix.ColumnsIndexes, Is.SameAs(columns));
            Assert.That(matrix.Values, Is.SameAs(data));
        }

        #if SAFE

        /// <summary>
        ///     Tests the constructor when rowsCount parameter is negative or equal to zero.
        /// </summary>
        /// <param name="rowsCount">
        ///     The rows count.
        /// </param>
        [Test]
        public void WhenRowsCountParameterIsOutOfRange([Values(0, -1)] int rowsCount)
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columnsIndexes = new[] { 0 };

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(rowsCount, 1, rowsBegins, columnsIndexes),
                Throws.TypeOf<NegativeOrZeroSizeException>().With.Property("ParamName").EqualTo("rowsCount"));
        }

        /// <summary>
        ///     Tests the constructor when columnsCount parameter is negative or equal to zero.
        /// </summary>
        /// <param name="columnsCount">
        ///     The columns count.
        /// </param>
        [Test]
        public void WhenColumnsCountParameterIsOutOfRange([Values(0, -1)] int columnsCount)
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columnsIndexes = new[] { 0 };

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, columnsCount, rowsBegins, columnsIndexes),
                Throws.TypeOf<NegativeOrZeroSizeException>().With.Property("ParamName").EqualTo("columnsCount"));
        }

        /// <summary>
        ///     Tests the constructor when rowsBegins parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenRowsBeginsParameterIsNull()
        {
            // Arrange
            var columnsIndexes = new[] { 0 };

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, 1, null, columnsIndexes),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("rowsBegins"));
        }

        /// <summary>
        ///     Tests the constructor when rowsBegins parameter has the number of elements less than rowsCount plus 1.
        /// </summary>
        [Test]
        public void WhenRowsBeginsParameterHasNoEnoughElements()
        {
            // Arrange
            var rowsBegins = new[] { 0 };

            // length less than rowsCount + 1
            var columnsIndexes = new[] { 0 };

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, 1, rowsBegins, columnsIndexes),
                Throws.TypeOf<NoEnoughElementsException>().With.Property("ParamName").EqualTo("rowsBegins"));
        }

        /// <summary>
        ///     Tests the constructor when columnsIndexes parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenColumnsIndexesParameterIsNull()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, 1, rowsBegins, null),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("columnsIndexes"));
        }

        /// <summary>
        ///     Tests the constructor when columnsIndexes parameter has the number of elements less than
        ///     rowsBegins[rowsCount] - rowsBegins[0].
        /// </summary>
        [Test]
        public void WhenColumnsIndexesParameterHasNoEnoughElements()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };

            // length less than 1 - 0
            var columnsIndexes = new int[0];

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, 1, rowsBegins, columnsIndexes),
                Throws.TypeOf<NoEnoughElementsException>().With.Property("ParamName").EqualTo("columnsIndexes"));
        }

        /// <summary>
        ///     Tests the constructor when data parameter is not <see langword="null"/> and has the number of elements less
        ///     than rowsBegins[rowsCount] - rowsBegins[0].
        /// </summary>
        [Test]
        public void WhenDataParameterIsNotNullAndHasNoEnoughElements()
        {
            // Arrange
            var rowsBegins = new[] { 0, 1 };
            var columnsIndexes = new[] { 0 };

            // length less than 1 - 0
            var data = new object[0];

            // Act and Assert
            Assert.That(
                () => new CrsSparseMatrix<object>(1, 1, rowsBegins, columnsIndexes, data),
                Throws.TypeOf<NoEnoughElementsException>().With.Property("ParamName").EqualTo("data"));
        }

        #endif
    }
}